#ifndef LIST_H
#define LIST_H
#pragma once
#include"Node.h"

template <class T>
class List {
private:
    // data members
    Node<T> *m_head;   // point to the first node of the list
    int m_count;  // number of nodes in the list
public:
    // safety features for linked structures
    List();                              // construct an empty List object
    List(const List<T> &src_list);                                // the copy constructor
    ~List();                             // the destructor
    List<T>& operator =(const List<T> &src_list);            // the overloaded assignment operator
    // methods
	// inline function, inspector
	inline int GetSize() const { return m_count; }
	inline bool IsEmpty() const { return m_count == 0; }
	//bool IsExist(const T &x);
	//ErrorCode Append_List_No_Reapt(const List<T> &the_list );

    void Clear();
    ErrorCode Insert(int position, const T &data);
    ErrorCode Remove(int position);
    ErrorCode Remove(int position, T &data);
    ErrorCode Replace(int position, const T &data);
    ErrorCode Retrieve(int position, T &data) const;
    void Traverse(void (*VisitFunc)(const T &));
};

template <class T>
List<T>::List()                              // construct an empty List object


{
	m_count=0;
	m_head=NULL;
}

template <class T>
List<T>::List(const List<T> &the_list)       // the copy constructor
{
	if ( the_list.IsEmpty() )
	{
		m_head  = NULL;
		m_count = 0;
	}
	else
	{
		Node<T> *source_node = the_list.m_head;
		Node<T> *target_node = new Node<T>(source_node->data);
		m_head = target_node;
		while( source_node->next != NULL )
		{
			source_node       = source_node->next;
			target_node->next = new Node<T>(source_node->data);
			target_node       = target_node->next;
		}
		m_count = the_list.m_count;
	}
}

template <class T>
List<T>::~List()                             // the destructor
{
	Clear();
}

// the overloaded assignment operator
template <class T>
List<T> &List<T>::operator=(const List<T> &src_list)
{
    if (this != &src_list)
    {
        if (m_head)    // if the original list is existed, clear it
        {
            Clear();
        }
	    if ( !src_list.IsEmpty() )
	    {
		    Node<T> *source_node = src_list.m_head;
		    Node<T> *target_node = new Node<T>(source_node->data);
		    m_head = target_node;
		    while( source_node->next != NULL )
		    {
			    source_node       = source_node->next;
			    target_node->next = new Node<T>(source_node->data);
			    target_node       = target_node->next;
		    }
		    m_count = src_list.m_count;
	    }
    }
	return *this;
}

template< class T >
void List<T>::Clear()
{
    Node<T> *oldNode = m_head;
	Node<T> *temp = oldNode;
	while ( temp != NULL )
	{
		temp = temp->next;
		delete oldNode;
        oldNode = temp;
	}
	m_head  = NULL;
	m_count = 0;
}

template< class T >
ErrorCode List<T>::Insert(int position, const T &data)
{
	if(position < 0 || position > m_count)   return error_range;
	if(position == 0)
	{
		Node<T> *new_node = new Node<T>(data);
		new_node->next = m_head;
		m_head = new_node;
		m_count++;
		return error_success;
	}
	else if(position == m_count)
	{
		Node<T> *new_node = new Node<T>(data);
		Node<T> *old_node = m_head;
		for(int i = 0; i < m_count-1; i++)
		{
			old_node = old_node->next;
		}
		old_node->next = new_node;
		m_count ++;
		return error_success;
	}
    else
    {
	    Node<T> *new_node = new Node<T>(data);
	    Node<T> *old_node = m_head;
	    for (int i = 0; i < position - 1; i ++)
	    {
		    old_node = old_node-> next;
	    }
	    new_node->next = old_node->next;
	    old_node->next = new_node;
	    m_count++;
	    return error_success;
    }
}

template< class T >
ErrorCode List<T>::Remove(int position)
{
    if(m_count == 0) return error_underflow;
	if(position < 0 || position > m_count - 1)return error_range;
    if(position == 0)
    {
        Node<T> *temp = m_head;
        m_head = temp->next;
        delete temp;
        m_count --;
        return error_success;
    }
    else
    {
	    Node<T> *pre_node = m_head;
	    for(int i = 0; i < position - 1; i++)
	    {
		    pre_node = pre_node->next;
	    }
        Node<T> *del_node = pre_node->next;
	    pre_node->next = del_node->next;
	    delete del_node;
	    m_count--;
	    return error_success;
    }
}

template< class T >
ErrorCode List<T>::Remove(int position, T &data)
{
    if(m_count == 0) return error_underflow;
	if(position < 0 || position > m_count - 1)return error_range;
    if(position == 0)
    {
        Node<T> *temp = m_head;
        m_head = temp->next;
        data = temp->data;
        delete temp;
        m_count --;
        return error_success;
    }
    else
    {
	    Node<T> *pre_node = m_head;
	    for(int i = 0; i < position - 1; i++)
	    {
		    pre_node = pre_node->next;
	    }
        Node<T> *del_node = pre_node->next;
	    pre_node->next = del_node->next;
        data = del_node->data;
	    delete del_node;
	    m_count--;
	    return error_success;
    }
}

template< class T >
ErrorCode List<T>::Replace(int position, const T &data)
{
    if(m_count == 0) return error_underflow;
	if(position < 0 || position > m_count - 1)return error_range;
	Node<T> *rep_node = m_head;
	for(int i= 0; i < position; i++)
	{
		rep_node = rep_node->next;
	}
	rep_node->data = data;
	return error_success;
}

template< class T >
ErrorCode List<T>::Retrieve(int position, T &data) const
{
    if (m_count == 0) return error_underflow;
	if(position < 0 || position > m_count - 1)return error_range;
	Node<T> *ret_node = m_head;
	for(int i= 0; i < position; i ++)
	{
		ret_node = ret_node->next;
	}
	data = ret_node->data;
	return error_success;
}

template< class T >
void List<T>::Traverse(void (*VisitFunc)(const T &))
{
	Node<T> *current_node = m_head;
	while( current_node != NULL )
	{
		(*VisitFunc)(current_node->data);
		current_node = current_node->next;
	}
}
/*
template< class T >
bool List<T>::IsExist(const T &x)
{
	int i;

	T data;
	for ( i = 0; i < GetSize(); i++ )
	{
		Retrieve(i, data);
		if ( data == x ) return true;
	}
	return false;
}

template< class T >
ErrorCode List<T>::Append_List_No_Reapt(const List<T> &the_list )
{
	int i;
	int n = the_list.GetSize();
	T data;
	for ( i = 0; i < n; i++ )
	{
		the_list.Remove(0, data);
		if ( !IsExist(data) )
		{
			Insert(GetSize(), data);
		}
	}
	return error_success;
}
*/
#endif

